﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Reticle.Core;
using System.Windows.Forms;
using BNSharp;
using System.Collections;
using System.Net;
using System.IO;
using System.Diagnostics;

namespace UGnome
{
    public class Plugin : IPlugin
    {
        Manager manager { get; set; }

        public IHost Bot;
        public ToolStripMenuItem myMenu = new ToolStripMenuItem();

        public Queue Q { get; set; }
        public System.Timers.Timer T { get; private set; }
        public int Delay { get; private set; }
        public int QDelay { get; private set; }
        public int ClanDelay { get; private set; }
        public string Realm { get; private set; }
        public List<string> PubChannels { get; set; }
        public int MinDelay { get; private set; }
        public int MaxDelay { get; private set; }
        public string Product { get; private set; }
        public string Username { get; private set; }
        public string Users { get; private set; }
        public int UsersCount { get; private set; }
        public string BotChannel { get; private set; }
        public string BotProduct { get; private set; }
        public bool IsPubChannel { get; private set; }
        public bool SavePubData { get; set; }
        public bool StartOnConnect { get; set; }
        public int Counter { get; private set; }
        public int NewChannelDelay { get; private set; }
        public string Password { get; set; }

        public string gUrl { get; set; }

        #region IPlugin Members

        public string Author
        {
            get { return "Scope"; }
        }

        public string Name
        {
            get { return "UGnome"; }
        }

        public string Description
        {
            get { return "Roam Battle.net collecting various user/channel data."; }
        }

        // Do not use spaces in Filename
        public string Filename
        {
            get { return "UGnome.dll"; }
        }

        public string URL
        {
            get { return "http://www.bnetweb.org"; }
        }

        public void Initialize(IHost host)
        {
            Bot = host;
            manager = new Manager(this);
            PubChannels = new List<string>();

            // Create the plugin menu (and submenus)
            EventHandler e = new EventHandler(myMenus_Click);
            myMenu.Text = "UGnome";
            myMenu.DropDownItems.Add(PluginFunctions.NewToolMenu("Start", "Start", e));
            myMenu.DropDownItems.Add(PluginFunctions.NewToolMenu("Stop", "Stop", e));
            myMenu.DropDownItems.Add(new ToolStripSeparator());
            myMenu.DropDownItems.Add(PluginFunctions.NewToolMenu("Config", "Config", e));
            Bot.SetPluginMenu(myMenu);

            Q = new Queue();
            T = new System.Timers.Timer();
            T.Elapsed += T_Tick;
            T.Interval = 1000;
            Delay = 1;
            QDelay = 3;
            ClanDelay = 120;
            NewChannelDelay = 3;
            Counter = 0;

            ReloadSettings();

            if (StartOnConnect)
            {
                if (Bot.IsConnected())
                {
                    T.Start();
                }
            }

            // create the full available channels list
            manager.PopulateAllChannels(gUrl, Realm);
        }

        // fires when the plugin is unloaded
        public void Unload()
        {
            Bot.UnloadPlugin();
        }

        // handles the click event of each menu item
        void myMenus_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem m = (ToolStripMenuItem)sender;
            switch (m.Name)
            {
                case "Start":
                    Bot.AddChat("#00FF00", "[UGnome] Started.");
                    T.Start();
                    break;
                case "Stop":
                    Bot.AddChat("#F0493C", "[UGnome] Stopped.");
                    T.Stop();
                    break;
                case "Config":
                    UGnome gnome = new UGnome(this);
                    gnome.ShowDialog();
                    break;
            }
        }

        // make sure the plugin settings exist before attempting the grab them
        public void CreateSettings()
        {
            if (String.IsNullOrEmpty((string)Bot.GetPluginSetting("password")))
            {
                Bot.SavePluginSetting("password", "changeme");
            }

            if (String.IsNullOrEmpty((string)Bot.GetPluginSetting("url")))
            {
                Bot.SavePluginSetting("url", "http://www.bnetweb.org/gnome.php");
            }

            if (String.IsNullOrEmpty((string)Bot.GetPluginSetting("mindelay")))
            {
                Bot.SavePluginSetting("mindelay", "6");
            }

            if (String.IsNullOrEmpty((string)Bot.GetPluginSetting("maxdelay")))
            {
                Bot.SavePluginSetting("maxdelay", "10");
            }

            if (String.IsNullOrEmpty((string)Bot.GetPluginSetting("savepubdata")))
            {
                Bot.SavePluginSetting("savepubdata", "0");
            }

            if (String.IsNullOrEmpty((string)Bot.GetPluginSetting("startonconnect")))
            {
                Bot.SavePluginSetting("startonconnect", "1");
            }

            if (String.IsNullOrEmpty((string)Bot.GetPluginSetting("pubchannels")))
            {
                Bot.SavePluginSetting("pubchannels", "Clan Recruitment|Frozen Throne USA-1|Frozen Throne USA-2|Frozen Throne USA-3|Frozen Throne USA-4|Frozen Throne USA-5|Frozen Throne USA-6|Frozen Throne USA-7|Frozen Throne USA-8|Frozen Throne USA-9|Frozen Throne USA-10|Open Tech Support|Public Chat 1|Public Chat 2|Peon Hall|Human Castle|Orc Stronghold|Undead Necropolis|Night Elf Tree of Life|Dragon Roost|Warcraft III USA-1|Warcraft III USA-2|Warcraft III USA-3|Sex|Sex2|Brood War USA-1|Brood War USA-2|Brood War USA-3|Brood War USA-4|Brood War USA-5");
            }
        }

        public void ReloadSettings()
        {
            CreateSettings();

            Password = (string)Bot.GetPluginSetting("password");
            gUrl = (string)Bot.GetPluginSetting("url");
            MinDelay = Convert.ToInt32((string)Bot.GetPluginSetting("mindelay"));
            MaxDelay = Convert.ToInt32((string)Bot.GetPluginSetting("maxdelay"));
            //Realm = (string)Bot.GetPluginSetting("realm");
            Realm = manager.GetRealmFromServer((string)Bot.GetConfigSetting("server"));
            Product = (string)Bot.GetConfigSetting("product");
            Username = (string)Bot.GetConfigSetting("username");
            BotProduct = (string)Bot.GetConfigSetting("product");
            Users = "";
            UsersCount = 0;

            string pubData = (string)Bot.GetPluginSetting("savepubdata");

            SavePubData = false;

            if (pubData == "1")
            {
                SavePubData = true;
            }

            string startonconnect = (string)Bot.GetPluginSetting("startonconnect");

            StartOnConnect = false;

            if (startonconnect == "1")
            {
                StartOnConnect = true;
            }

            string pubchan = (string)Bot.GetPluginSetting("pubchannels");
            string[] channels = pubchan.Split('|');

            // clear old PubChannels
            PubChannels.Clear();
            foreach (string channel in channels)
            {
                PubChannels.Add(channel);
            }
        }

        public void SaveSettings()
        {
            if (StartOnConnect)
            {
                Bot.SavePluginSetting("startonconnect", "1");
            }
            else
            {
                Bot.SavePluginSetting("startonconnect", "0");
            }

            if (SavePubData)
            {
                Bot.SavePluginSetting("savepubdata", "1");
            }
            else
            {
                Bot.SavePluginSetting("savepubdata", "0");
            }

            string data = "";
            foreach (string channel in PubChannels)
            {
                data += String.Format("{0}|", channel);
            }
            if (!String.IsNullOrEmpty(data))
            {
                data = data.Remove(data.Length - 1, 1);
            }

            Bot.SavePluginSetting("pubchannels", data);

            Bot.SavePluginSetting("password", Password);
            Bot.SavePluginSetting("url", gUrl);
        }

        // grab random public channel to join
        public string RandomPubChannel()
        {
            int randomInt = new Random().Next(PubChannels.Count);

            return PubChannels[randomInt];
        }

        // return random # to wait to join next channel
        public int RandomDelay()
        {
            int randomInt = new Random().Next(MinDelay, MaxDelay);

            return randomInt;
        }

        // remove * from Diablo 2 usernames
        public string FixUsername(string username)
        {
            if (username.StartsWith("*"))
            {
                return username.Replace("*", "");
            }

            return username;
        }

        // tick the timer
        public void T_Tick(object sender, EventArgs e)
        {
            if (!Bot.IsConnected())
            {
                return;
            }

            // take 1 away from delay (signifies one second)
            Delay--;
            QDelay--;
            ClanDelay--;

            if (ClanDelay <= 0)
            {
                // refresh clan info for the next clan on the list
                if (manager.ClanChannel.Count > 0)
                {
                    string bnetURL = "http://" + manager.GetClanRealm(Realm) + ".battle.net/war3/ladder/w3xp-clan-profile.aspx?ClanTag=" + manager.Encode(manager.ClanChannel[0]) + "&Gateway=" + manager.Encode(Realm) + "&SortField=rank&SortDir=Desc&PageNo=1";

                    manager.GrabClanInfo(bnetURL, manager.ClanChannel[0], Realm, gUrl);

                    manager.ClanChannel.RemoveAt(0);
                }
                else
                {
                    HttpRequest send = new HttpRequest(gUrl + String.Format("?p={0}&clanchannels&realm={1}", manager.Encode(Password), Realm), HttpRequestId.ClanList);
                    Q.Enqueue(send);
                }

                ClanDelay = 120;
            }

            if (QDelay <= 0)
            {
                if (Q.Count > 0)
                {
                    HttpRequest result = (HttpRequest)Q.Dequeue();
                    manager.Send(result);
                    //string sendurl = (string)Q.Dequeue();
                    //manager.Send(sendurl, HttpRequestId.Packet2);
                }

                QDelay = 3;
            }

            // Join next channel
            if (Delay <= 0)
            {
                // make sure the next channel isn't null or the current channel
                if (manager.NextChannel.Count > 0)
                {
                    if (!string.IsNullOrEmpty(manager.NextChannel[0]) && manager.NextChannel[0] != Bot.CurrentChannel())
                    {
                        // join the channel
                        BotChannel = manager.NextChannel[0];
                        Bot.AddChat("white", "/j " + BotChannel);
                        Bot.Send(String.Format("/j {0}", BotChannel));
                    }
                    else
                    {
                        string rchannel = RandomPubChannel();
                        Bot.AddChat("white", "/j " + rchannel);
                        Bot.Send(String.Format("/j {0}", rchannel));
                    }
                    // remove channel from list
                    manager.NextChannel.RemoveAt(0);
                }
                else
                {
                    string rchannel = RandomPubChannel();
                    Bot.AddChat("white", "/j " + rchannel);
                    Bot.Send(String.Format("/j {0}", rchannel));
                    //Bot.AddChat("#00FF00", "[UGnome] Requesting new channel list...");
                    
                    NewChannelDelay--;
                    
                    if (NewChannelDelay <= 0)
                    {
                        HttpRequest send = new HttpRequest(gUrl + String.Format("?p={0}&nextchannel&realm={1}", manager.Encode(Password), Realm), HttpRequestId.RoamList);
                        Q.Enqueue(send);

                        NewChannelDelay = 3;
                    }
                }

                Delay = RandomDelay();
            }
        }

        #region Battle.net Events
        // When the bot establishes a connection to Battle.net
        public void Connected(object sender, EventArgs e)
        {
            
        }

        // When the bot is disconnected from Battle.net (for any reason)
        public void Disconnected(object sender, EventArgs e)
        {
            // Stop Timer
            T.Stop();
        }

        // When the bot receives an error from Battle.net (i.e. no friends)
        public void ServerErrorReceived(object sender, ServerChatEventArgs e)
        {
            if (e.Text.Contains("That channel is restricted.") && !IsPubChannel)
            {
                HttpRequest send = new HttpRequest(gUrl + String.Format("?p={0}&channel={1}&realm={2}&restricted=1", manager.Encode(Password), manager.Encode(BotChannel), manager.Encode(Realm)), HttpRequestId.RoamList);
                Q.Enqueue(send);
            }
        }

        // When the bot receives information (i.e. friends list)
        public void InformationReceived(object sender, ServerChatEventArgs e)
        {

        }

        // When the bot enters chat
        public void EnteredChat(object sender, EnteredChatEventArgs e)
        {
            // start the timer
            if (StartOnConnect)
            {
                T.Start();
            }
        }

        // When the bot joins a channel (everytime it joins a channel)
        public void JoinedChannel(object sender, ServerChatEventArgs e)
        {
            // reset counter so users talking affects gnome's time in channel
            Counter = 0;

            string channel = e.Text.ToLower();

            if (channel == "clan recruitment")
            {
                IsPubChannel = true;
            }
            else if (channel.StartsWith("op ") || channel.StartsWith("clan "))
            {
                IsPubChannel = false;
            }
            else
            {
                IsPubChannel = true;
            }

            if (!IsPubChannel)
            {
                HttpRequest send = new HttpRequest(gUrl + String.Format("?p={0}&channel={1}&realm={2}&restricted=0", manager.Encode(Password), manager.Encode(e.Text), manager.Encode(Realm)), HttpRequestId.RoamList);
                Q.Enqueue(send);
            }
        }

        // When a user joins a channel
        public void UserJoined(object sender, UserEventArgs e)
        {
            Counter++;
            if (Counter == 1)
            {
                Delay += 4;
            }
            else if (Counter == 2)
            {
                Delay += 2;
            }


            string product = e.User.Stats.Product.ProductCode;
            string clan = "";

            // Get Clan Tag (if applicable)
            if (product == "WAR3" || product == "W3XP")
            {
                string[] stats = e.User.Stats.LiteralText.Split(new char[] { ' ' });

                if (stats.Length == 4)
                {
                    clan = manager.ReverseString(stats[3]);
                    string channel = "Clan " + clan;

                    if (!manager.FindAllChannel(channel) && clan.Length > 1 && clan.Length < 5)
                    {
                        manager.AddAllChannel(channel);

                        string bnetURL = "http://" + manager.GetClanRealm(Realm) + ".battle.net/war3/ladder/w3xp-clan-profile.aspx?ClanTag=" + manager.Encode(clan) + "&Gateway=" + manager.Encode(Realm) + "&SortField=rank&SortDir=Desc&PageNo=1";

                        manager.GrabClanInfo(bnetURL, channel, Realm, gUrl);
                    }
                }
            }
        }

        // When a user leaves the channel
        public void UserLeft(object sender, UserEventArgs e)
        {

        }

        // All users currently present in the channel (when the bot first joins)
        public void UserShown(object sender, UserEventArgs e)
        {
            // don't save #2, #3, etc
            if (e.User.Username.Contains("#"))
            {
                return;
            }

            string product = e.User.Stats.Product.ProductCode;
            string clan = "";

            // Get Clan Tag (if applicable)
            if (product == "WAR3" || product == "W3XP")
            {
                string[] stats = e.User.Stats.LiteralText.Split(new char[] { ' ' });

                if (stats.Length == 4)
                {
                    clan = manager.ReverseString(stats[3]);
                    string channel = "Clan " + clan;

                    if (!manager.FindAllChannel(channel) && clan.Length > 1 && clan.Length < 5)
                    {
                        manager.AddAllChannel(channel);

                        string bnetURL = "http://" + manager.GetClanRealm(Realm) + ".battle.net/war3/ladder/w3xp-clan-profile.aspx?ClanTag=" + manager.Encode(clan) + "&Gateway=" + manager.Encode(Realm) + "&SortField=rank&SortDir=Desc&PageNo=1";

                        manager.GrabClanInfo(bnetURL, channel, Realm, gUrl);
                    }
                }
            }

            if (SavePubData && IsPubChannel || !IsPubChannel)
            {
                // we haven't reached end of channel list, keep building string
                if (Username.ToLower() != FixUsername(e.User.Username.ToLower()))
                {
                    // increment number of users in channel by 1
                    UsersCount++;
                    // continue building user string
                    Users += String.Format("&user{0}={1}*{2}*{3}*{4}*{5}*{6}",
                        UsersCount.ToString(), manager.Encode(manager.AddAppend(FixUsername(e.User.Username), e.User.Stats.Product.ProductCode, Realm)),
                        manager.Encode(e.User.Stats.Product.ProductCode), e.User.Ping, manager.Encode(Bot.CurrentChannel()),
                        manager.Encode(clan), manager.Encode(e.User.Flags.ToString()));
                }
                else if (Username.ToLower() == FixUsername(e.User.Username.ToLower()))
                {
                    if (!String.IsNullOrEmpty(Users))
                    {
                        HttpRequest send = new HttpRequest(gUrl + String.Format("?p={0}&users&realm={1}{2}", manager.Encode(Password), manager.Encode(Realm), Users), HttpRequestId.Null);
                        Q.Enqueue(send);
                        //manager.Send(send);
                    }

                    Users = "";
                    UsersCount = 0;
                }
            }
        }

        // When a person is op'd, de-op'd, etc
        public void UserFlagsChanged(object sender, UserEventArgs e)
        {

        }

        // When someone speaks
        public void UserSpoke(object sender, ChatMessageEventArgs e)
        {
            manager.FindChannels(e.Text, gUrl, Realm);
            //Q.Enqueue(new HttpRequest("http://ugnome.bnetweb.org/gnome.php?blah", HttpRequestId.Null));

            Counter++;
            if (Counter == 1)
            {
                Delay += 4;
            }
            else if (Counter == 2)
            {
                Delay += 2;
            }
        }

        // When someone emotes
        public void UserEmoted(object sender, ChatMessageEventArgs e)
        {
            manager.FindChannels(e.Text, gUrl, Realm);

            Counter++;
            if (Counter == 1)
            {
                Delay += 4;
            }
            else if (Counter == 2)
            {
                Delay += 2;
            }
        }

        // When the bot talks
        public void MessageSent(object sender, ChatMessageEventArgs e)
        {

        }

        // When you receive a whisper
        public void WhisperReceived(object sender, ChatMessageEventArgs e)
        {
            manager.FindChannels(e.Text, gUrl, Realm);

            if (e.Text.ToLower().Contains("ignore clan"))
            {
                try
                {
                    string[] splt = e.Text.Split(' ');
                    string channel = splt[2];

                    HttpRequest send = new HttpRequest(gUrl + String.Format("?p={0}&removechannel={1}&realm={2}&chief={3}", manager.Encode(Password), manager.Encode(channel), manager.Encode(Realm), manager.Encode(FixUsername(e.Username))), HttpRequestId.Null);
                    Q.Enqueue(send);
                }
                catch (Exception)
                {

                }
            }
        }

        // When you send a whisper
        public void WhisperSent(object sender, ChatMessageEventArgs e)
        {

        }
        #endregion

        #endregion
    }
}
